package org.security.jwt;

import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.JWT;

import lombok.Data;
import org.security.config.FreeProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @author jt
 * @date 2024/7/21 16:53
 */
@Component
 public class JwtUtil {

     @Autowired
     private FreeProperties freeProperties;

     private static FreeProperties properties;


    private static String jwtSecret = "UACTokenSecret###";

        //过期时间设置为一周
        public static final Integer expireInSec = 604800;

        public static final String USER_ID_KEY = "userId";

        public static final String SCOPES = "scopes";

        public static final String SYS_NODE_CODE_KEY = "sysNodeCode";

        private final Integer REFRESH_TOKEN_EXPIRE_IN_SEC = 3600 * 24 * 7;

        public static String createToken(String tid, String sysNodeCode, UserInfo userInfo, Instant issueAt, Instant expireAt) {
            Algorithm algorithm = Algorithm.HMAC256(jwtSecret);
            return JWT.create()
                    .withJWTId(tid)
                    .withClaim(SYS_NODE_CODE_KEY, sysNodeCode)
                    .withClaim(USER_ID_KEY, userInfo.getId())
                    .withClaim(SCOPES,userInfo.getScopes())
                    .withIssuedAt(Date.from(issueAt))
                    .withExpiresAt(Date.from(expireAt))
                    .sign(algorithm);
        }

        public TokenInfo generateToken(String sysNodeCode, UserInfo userInfo) {
            Instant now = Instant.now();
            Instant expireAt = now.plusSeconds(expireInSec);
            Instant refreshTokenExpireAt = now.plusSeconds(REFRESH_TOKEN_EXPIRE_IN_SEC);
            String tid = UUID.randomUUID().toString();
            String token = createToken(tid, sysNodeCode, userInfo, now, expireAt);
            String refreshToken = createToken(tid, sysNodeCode, userInfo, now, refreshTokenExpireAt);
            TokenInfo res = new TokenInfo();
            res.setId(tid);
            res.setExpireIn(expireInSec.longValue());
            res.setRefreshTokenExpireIn(REFRESH_TOKEN_EXPIRE_IN_SEC.longValue());
            res.setToken(token);
            res.setExpireAt(expireAt.getEpochSecond());
            res.setRefreshToken(refreshToken);
            res.setRefreshTokenExpireAt(refreshTokenExpireAt.getEpochSecond());
            return res;
        }

        public static JwtPayloadInfo verify(String token) {
        Instant now = Instant.now();
            try {
                Algorithm algorithm = Algorithm.HMAC256(jwtSecret);
                JWTVerifier verifier = JWT.require(algorithm)
                    .acceptExpiresAt(now.getEpochSecond())
                        .withClaimPresence(USER_ID_KEY)
                        .withClaimPresence(SYS_NODE_CODE_KEY)
                        .withClaimPresence(SCOPES)
                        .withClaimPresence("exp")
                        .withClaimPresence("iat")
                        .build();
                DecodedJWT jwt = verifier.verify(token);
                JwtPayloadInfo info = new JwtPayloadInfo();
                info.setId(jwt.getId());
                info.setSysNodeCode(jwt.getClaim(SYS_NODE_CODE_KEY).asString());
                info.setUserId(jwt.getClaim(USER_ID_KEY).asString());
                info.setScopes(jwt.getClaim(SCOPES).asList(String.class));
                info.setIssueAt(jwt.getIssuedAt().getTime());
                info.setExpireAt(jwt.getExpiresAt().getTime());
                return info;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public Integer getInfoFromToken(String token, String filed) {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(filed).asInt();
        }

    @PostConstruct
    public void setProperties(){
        this.properties = freeProperties;
    }

        @Data
        public static class JwtPayloadInfo {

            private String id;
            private String sysNodeCode;
            private String userId;
            private List<String> scopes;
            private Long expireAt;
            private Long issueAt;
        }
}
